
from itertools import product
import numpy as np

sx, sy, sz = size = (3, 3,2)
bi = range(2)

def myproduct(a, b):
    for t in product(*[bi]*(a * b)):
        yield [[t[a * j + i] for i in range(a)] for j in range(b)]



def get(l, sx, sy, x, y):
    x = x  % sx
    y = y % sy
    try:
        return l[y][x]
    except Exception as e:
        print(sx, sy, "l:", len(l[0]), len(l))
        raise e



def check(l, sx, sy, bx, by):
    p1 = get(l, sx, sy, bx, by)
    p2 = get(l, sx, sy, bx+1, by)
    p3 = get(l, sx, sy, bx, by+1)
    p4 = get(l, sx, sy, bx+1, by+1)
    if (p1, p2, p3, p4) == (1, 0, 0, 1) or (p1, p2, p3, p4) == (0, 1, 1, 0):
        return False
    else:
        return True


def check2(sx, sy):
    def f(l):
        for x in range(sx):
            for y in range(sy):
                b = check(l, sx, sy, x, y)
                if not b:
                    return False
        return True
    return f


rxy = list(filter(check2(sx, sy), myproduct(sx, sy)))
rxz = list(filter(check2(sx, sz), myproduct(sx, sz)))
ryz = list(filter(check2(sy, sz), myproduct(sy, sz)))




print(len(rxy), len(rxz), len(ryz))
#exit()



# 单维度情况完成


def doz(m, pat):
    for y, pp in enumerate(pat):
        for x, v in enumerate(pp):
            if v:
                m[:, y, x] = 1


def dox(m, pat):
    for z, pp in enumerate(pat):
        for y, v in enumerate(pp):
            if v:
                m[z, y, :] = 1

def doy(m, pat):
    for z, pp in enumerate(pat):
        for x, v in enumerate(pp):
            if v:
                m[z, :, x] = 1




def gen(pat1, pat2, pat3):
    m = np.zeros(size[::-1], dtype=int)
    dox(m, pat1)
    doy(m, pat2)
    doz(m, pat3)
    return m

def multi(m):
    acc = []
    acc.append(m)
    for tt in range(1, sz):
        acc.append(np.roll(m, tt, axis=0))
    for mm in acc[:]:
        for tt in range(1, sy):
            acc.append(np.roll(m, tt, axis=1))
    for mm in acc[:]:
        for tt in range(1, sx):
            acc.append(np.roll(m, tt, axis=2))
    for mm in acc[:]:
        acc.append(mm[:, :, ::-1])
    for mm in acc[:]:
        acc.append(mm[:, ::-1, :])
    if sx == sy:
        for mm in acc[:]:
            acc.append(np.transpose(mm, (0, 2, 1)))
    return (tu(x) for x in acc)


def tu(m):
    return tuple(m.flatten())



def check3(m):
    for tt in range(sz):
        tt2 = (tt + 1) % sz
        b = np.all(m[tt, :, :] == m[tt2, :, :])
        if b:return True
    for tt in range(sy):
        tt2 = (tt + 1) % sy
        b = np.all(m[:, tt, :] == m[:, tt2, :])
        if b:return True
    for tt in range(sx):
        tt2 = (tt + 1) % sx
        b = np.all(m[:, :, tt] == m[:, :, tt2])
        if b:return True

    return False



from mat_encode import en

def get3(m, x, y, z):
    #x, y, z = p
    return m[sy * sx * z + sx * y + x]

def ennn(m):
    mat = [[[get3(m, x, y, z) for x in range(sx)] for y in range(sy)] for z in range(sz)]
    return en(mat)

with open(f"yinyangplus{sx}{sy}{sz}.txt", 'w') as _:
    pass

fff = open(f"yinyangplus{sx}{sy}{sz}.txt", 'a')

final = []
finals = set()
i = 0
j = 0
count = len(rxy) * len(rxz) * len(ryz)
for pat1, pat2, pat3 in product(ryz, rxz, rxy):
    j += 1
    m = gen(pat1, pat2, pat3)
    mt = tu(m)
    if size == (3, 3, 3):
        if sum(mt) > 13:
            continue
    elif size == (3, 3, 2):
        if sum(mt) > 12:
            continue
    elif size == (3, 2, 3):
        if sum(mt) > 10:
            continue
    else:
        if sum(mt) > (sx * sy * sz * 0.75):
            continue

    if check3(m):
        continue


    if all(mmt not in finals for mmt in multi(m)):
        final.append(mt)
        finals.add(mt)
        s = ennn(mt)

        fff.write(s+'\n')

        i+= 1
        if i % 10 == 0:
            print(i, round(j/count, 5))
            fff.flush()

fff.flush()
fff.close()

print(len(final))


if "sort":
    from mat_encode import de, en


    l = []
    with open(f"yinyangplus{sx}{sy}{sz}.txt") as f:
        for line in f:
            m = de(line.strip())
            l.append(sum(sum(m, []), []))

    l.sort(key=lambda m: (sum(m), [1 - i for i in m]))

    print(l[:10])


    def get3(m, x, y, z):
        #x, y, z = p
        return m[sy * sx * z + sx * y + x]

    with open(f"yinyangplus{sx}{sy}{sz}sorted.txt", 'w') as f:
        for m in l:
            m = [[[get3(m, x, y, z) for x in range(sx)] for y in range(sy)] for z in range(sz)]
            f.write(en(m)+'\n')













